package com.ipan.kits.timer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 简单的任务实现
 * 使用Thread封装，在TaskImpl功能基础上，增加了调用recovery方法时候会立即执行一次任务，不需要等到间隔时间结束立即被执行；
 * 
 * @author iPan
 * @version 2018-08-21
 */
public class SimpleTask implements Task, Runnable {

	public static final int DEFAULT_PERIOD = 60 * 1000;
	
	/** 线程 */
	protected Thread thread = null;
	/** 时间段验证器 */
	protected TaskValidateable taskValidater;
	/** 任务执行器 */
	protected TaskRunnable runnable;
	/** 任务名称 */
	protected String name = null;
	/** 是否Daemon线程 */
	protected boolean isDaemon = false;
	/** 任务是否是循环执行；true 循环执行，false只执行一次  */
	protected boolean looped = false;
	/** 任务是否只做一次，使用锁； true 锁上，false 开锁 */
	protected boolean locked = false;
	/** 延迟时间 */
	protected long period = 0L;
	
	/** 是否启动；true 启动，false 关闭 */
	protected volatile boolean on = false;
	/** 是否中断；true 中断，false 未中断 */
	protected volatile boolean intercepted = false;
	/** 是否运行中；true 运行中，false 非运行中 */
	protected volatile boolean running = false;
	
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	
	public SimpleTask(TaskRunnable runnable) {
		this(runnable, new DefaultValidater(), Thread.currentThread().getClass().getSimpleName() + "-Timer", false, false);
	}
	
	public SimpleTask(TaskRunnable runnable, TaskValidateable taskValidater) {
		this(runnable, taskValidater, Thread.currentThread().getClass().getSimpleName() + "-Timer", false, false);
	}
	
	public SimpleTask(TaskRunnable runnable, TaskValidateable taskValidater, long period) {
		this(runnable, taskValidater, Thread.currentThread().getClass().getSimpleName() + "-Timer", false, period, false);
	}
	
	public SimpleTask(TaskRunnable runnable, TaskValidateable taskValidater, long period, boolean isLoop) {
		this(runnable, taskValidater, Thread.currentThread().getClass().getSimpleName() + "-Timer", isLoop, period, false);
	}
	
	public SimpleTask(TaskRunnable runnable, TaskValidateable taskValidater, String name, boolean isLoop, boolean isDaemon) {
		this(runnable, taskValidater, name, isLoop, DEFAULT_PERIOD, isDaemon);
	}
	
	public SimpleTask(TaskRunnable runnable, TaskValidateable taskValidater, String name, boolean isLoop, long period, boolean isDaemon) {
		this.runnable = runnable;
		this.taskValidater = taskValidater;
		this.name = name;
		this.looped = isLoop;
		this.period = period;
		this.isDaemon = isDaemon;
	}
	
	public void run() {
		logger.debug("call run thread:{}", Thread.currentThread().getName());
		while (this.on) {
			// 间隔时间（阻塞）
			try {
				Thread.sleep(this.period); // 等待的时候被stop
			} catch (InterruptedException e) {
				if (!this.on) { // 执行停止操作
					break;
				}
			}
			if (this.intercepted) { // 暂停中
				continue ;
			}
			
			synchronized(this) {
				this.running = true;
				boolean valied = taskValidater.validate();
				if (looped) {
					execLoopRun(valied); // （短期阻塞）
				} else {
					execRun(valied); // （短期阻塞）
				}
			}
			this.running = false;
		}
		this.thread = null;
	}
	
	// 在给定时间段内，只执行一次；
	// 如果一天内有多个执行时间段，那么每个时间段内都会执行一次；如果不希望这样，请重写该方法！
	protected void execRun(boolean valied) {
		// 在指定时间段内
		// 注意：当天，在该时间段内，如果容器重启，则会出现多次执行的情况；
		if (valied) {
			if (!locked) {
				logger.debug("定时器[{}]执行 ...", name);
				runnable.doRun();
				// 上锁
				locked = true;
				logger.info("定时器[{}]上锁 ...", name);
			}
		} else {
			if (locked) {
				// 开锁
				locked = false;
				logger.info("定时器[{}]开锁 ...", name);
			}
		}
	}
	
	// 验证通过后，只要timer延迟时间到了，就会执行；
	protected void execLoopRun(boolean valied) {
		if (valied) {
			logger.debug("定时器[{}]执行 ...", name);
			runnable.doRun();
		}
	}
	
	@Override
	public synchronized void start() {
		if (!this.on) {
			logger.debug("call start thread:{}", Thread.currentThread().getName());
			resetState();
			this.on = true;
			this.thread = new Thread(this, this.name);
			if (this.isDaemon) {
				this.thread.setDaemon(true);
			}
			thread.start();
			logger.info("定时器[{}]开启 ...", name);
		}
	}

	@Override
	public synchronized void pause() {
		logger.debug("call intercept thread:{}", Thread.currentThread().getName());
		this.intercepted = true;
		logger.info("定时器[{}]暂停 ...", name);
	}

	@Override
	public synchronized void recovery() { // 定时器恢复：当定时器在sleep时候，会立马执行一次任务；当定时器在运行时的时候，阻塞；
		if (!this.on) {
			throw new RuntimeException("任务未启动，无法恢复！");
		}
		logger.debug("call recovery thread:{}", Thread.currentThread().getName());
		resetState(); // locked=false; intercepted=false;
		thread.interrupt(); // 中断线程sleep
		logger.info("定时器[{}]恢复 ...", name);
	}

	@Override
	public synchronized void stop() {
		if (this.on) {
			logger.debug("call stop thread:{}", Thread.currentThread().getName());
			this.intercepted = true;
			this.on = false;
			thread.interrupt(); // 中断线程sleep
			logger.info("定时器[{}]关闭 ...", name);
		}
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public boolean isStart() {
		return on;
	}

	@Override
	public boolean isLoop() {
		return looped;
	}

	@Override
	public boolean isIntercept() {
		return intercepted;
	}

	@Override
	public boolean isValid() {
		return taskValidater.validate();
	}

	@Override
	public boolean isRunning() {
		return this.running;
	}
	
	@Override
	public void checkIntercept() throws TaskInterceptException {
		logger.debug("call checkIntercept thread:{}", Thread.currentThread().getName());
		if (this.intercepted) {
			throw new TaskInterceptException("系统需要中断！");
		}
	}
	
	// 状态复位
	protected void resetState() {
		this.locked = false;
		this.intercepted = false;
	}

	@Override
	public TaskValidateable getValidater() {
		return this.taskValidater;
	}

//	public static void main(String[] args) throws Exception {
//		Task task = new SimpleTask(new TaskRunnable() {
//			@Override
//			public void doRun() {
//				System.out.println("task run...");
//			}
//		}, TaskValidateable.NONE_VALIDATE, "my-task", true, 5000, true);
//		task.start();
//		Thread.sleep(6000);
//		System.out.println("main> recovery task");
//		task.recovery();
//		Thread.sleep(10000);
//		System.out.println("main> stop task");
//		task.stop();
//		System.out.println("main> exit");
//	}
	
}
